package wrapper

import (
	"gitee.com/ymofen/gobase"
	"github.com/suiyunonghen/dxsvalue"
	"net/url"
	"reflect"
	"sort"
	"strings"
	"time"
)

type SuperValue struct {
	useCache bool
	val      *dxsvalue.DxValue
}

func (this *SuperValue) UseCache() bool {
	return this.useCache
}

func (this *SuperValue) IsObject() bool {
	return this.val.DataType == dxsvalue.VT_Object
}

func (this *SuperValue) IsString() bool {
	return this.val.DataType == dxsvalue.VT_String || this.val.DataType == dxsvalue.VT_RawString
}

func (this *SuperValue) IsArray() bool {
	return this.val.DataType == dxsvalue.VT_Array
}

func (this *SuperValue) AsJSONBytesEx(escape bool, format bool) []byte {
	if this.val == nil {
		return nil
	}
	// sty := dxsvalue.JSE_NoEscape  // 有BUG,如果存在转义的时候 json.SetKeyString("param", "a\\\"b")
	sty := dxsvalue.JSE_OnlyAnsiChar
	if escape {
		sty = dxsvalue.JSE_AllEscape
	}

	if format {
		return dxsvalue.Value2FormatJson(this.val, sty, true, nil)
	} else {
		return dxsvalue.Value2Json(this.val, sty, true, nil)
	}
}

func (this *SuperValue) AsJSONBytes(escape bool) []byte {
	if escape {
		return dxsvalue.Value2Json(this.val, dxsvalue.JSE_AllEscape, true, nil)
	} else {
		return dxsvalue.Value2FormatJson(this.val, dxsvalue.JSE_OnlyAnsiChar, true, nil)
	}
}

func (this *SuperValue) From(val interface{}) {
	switch realv := val.(type) {
	case map[string]interface{}:
		for key, objv := range realv {
			this.val.SetKeyvalue(key, objv, this.val.ValueCache())
		}
	case *map[string]interface{}:
		for key, objv := range *realv {
			this.val.SetKeyvalue(key, objv, this.val.ValueCache())
		}
	case gobase.StrMap:
		for key, objv := range realv {
			this.val.SetKeyvalue(key, objv, this.val.ValueCache())
		}
	case []interface{}:
		for k, v := range realv {
			this.val.SetIndexvalue(k, v, this.val.ValueCache())
		}
	case string:
		this.val.SetString(realv)
	case uint:
		this.val.SetInt(int64(realv))
	case uint8:
		this.val.SetInt(int64(realv))
	default:
		//判断一下是否是结构体
		reflectv := reflect.ValueOf(val)
		if !reflectv.IsValid() {
			return
		}
		if reflectv.Kind() == reflect.Ptr {
			reflectv = reflectv.Elem()
		}
		cache := this.val.ValueCache()
		switch reflectv.Kind() {
		case reflect.String:
			this.val.SetString(reflectv.String())
		case reflect.Int, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int64:
			this.val.SetInt(reflectv.Int())
		case reflect.Uint, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint64:
			this.val.SetInt(int64(reflectv.Uint()))
		case reflect.Struct:
			rtype := reflectv.Type()
			for i := 0; i < rtype.NumField(); i++ {
				sfield := rtype.Field(i)
				fv := reflectv.Field(i)
				if fv.Kind() == reflect.Ptr {
					fv = fv.Elem()
				}
				switch fv.Kind() {
				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
					reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
					this.val.SetKeyCached(sfield.Name, dxsvalue.VT_Int, cache).SetInt(fv.Int())
				case reflect.Bool:
					this.val.SetKeyBool(sfield.Name, fv.Bool())
				case reflect.Float32:
					this.val.SetKeyFloat(sfield.Name, float32(fv.Float()))
				case reflect.Float64:
					this.val.SetKeyDouble(sfield.Name, fv.Float())
				case reflect.String:
					this.val.SetKeyString(sfield.Name, fv.String())
				default:
					if fv.CanInterface() {
						this.val.SetKeyvalue(sfield.Name, fv.Interface(), cache)
					}
				}
			}
		case reflect.Map:
			mapkeys := reflectv.MapKeys()
			if len(mapkeys) == 0 {
				return
			}
			kv := mapkeys[0]
			if kv.Type().Kind() == reflect.Ptr {
				kv = kv.Elem()
			}
			if kv.Kind() != reflect.String {
				return
			}

			for _, kv = range mapkeys {
				rvalue := reflectv.MapIndex(kv)
				if rvalue.Kind() == reflect.Ptr {
					rvalue = rvalue.Elem()
				}
				switch rvalue.Kind() {
				case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64,
					reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
					this.val.SetKeyCached(kv.String(), dxsvalue.VT_Int, cache).SetInt(rvalue.Int())
				case reflect.Bool:
					this.val.SetKeyBool(kv.String(), rvalue.Bool())
				case reflect.Float32:
					this.val.SetKeyFloat(kv.String(), float32(rvalue.Float()))
				case reflect.Float64:
					this.val.SetKeyDouble(kv.String(), rvalue.Float())
				case reflect.String:
					this.val.SetKeyString(kv.String(), rvalue.String())
				default:
					if rvalue.CanInterface() {
						this.val.SetKeyvalue(kv.String(), rvalue.Interface(), cache)
					}
				}
			}
		}
	}
}

func (this *SuperValue) GetKeys() []string {
	keys := make([]string, 0, this.Count())
	for i := 0; i < this.Count(); i++ {
		keys = append(keys, this.KeyNameByIndex(i))
	}
	return keys
}

func (this *SuperValue) AsJSONStringEx(escape bool, format bool) string {
	return string(this.AsJSONBytesEx(escape, format))
}

func (this *SuperValue) ArrayAsCsv(spliter string) string {
	var sb gobase.BytesBuilder
	n := 0
	this.Range(func(key string, val *SuperValue) bool {
		j := 0
		if n == 0 {
			j := 0
			val.Range(func(key string, val *SuperValue) bool {
				if j > 0 {
					sb.AppendStr(spliter)
				}
				sb.AppendStr(key)
				j++
				return true
			})
			sb.AppendStr("\r\n")
		}

		j = 0
		val.Range(func(key string, val *SuperValue) bool {
			if j > 0 {
				sb.AppendStr(spliter)
			}
			sb.AppendStr(val.String())
			j++
			return true
		})
		sb.AppendStr("\r\n")
		n++
		return true
	})
	return sb.String()
}

func (this *SuperValue) AsJSONString(escape bool) string {
	return string(this.AsJSONBytes(escape))
}

func (this *SuperValue) ForceByName(name string) *SuperValue {
	return NewSVFromVal(this.val.ForcePath(dxsvalue.VT_Object, name))
}

func (this *SuperValue) ForceByPath(path string) *SuperValue {
	return NewSVFromVal(this.val.ForcePath(dxsvalue.VT_Object, strings.Split(path, ".")...))
}

func (this *SuperValue) ForceArrayByPath(path string) *SuperValue {
	return NewSVFromVal(this.val.ForcePath(dxsvalue.VT_Array, strings.Split(path, ".")...))
}

func (this *SuperValue) FindByPath(path string) *SuperValue {
	val := this.val.ValueByPath(strings.Split(path, ".")...)
	if val == nil {
		return nil
	}
	return NewSVFromVal(val)
}

func (this *SuperValue) VarByName(name string) interface{} {
	v := this.val.ValueByName(name)
	return dxvalueToVar(v)
}

func (this *SuperValue) AsVar() interface{} {
	return dxvalueToVar(this.val)
}

func (this *SuperValue) VarByPath(path string) interface{} {
	v := this.val.ValueByPath(strings.Split(path, ".")...)
	return dxvalueToVar(v)
}

func (this *SuperValue) VarByIdx(idx int) interface{} {
	v := this.val.ValueByIndex(idx)
	return dxvalueToVar(v)
}

func (this *SuperValue) CheckFunc(path string, cb func(val interface{})) bool {
	findv := this.val.ValueByPath(strings.Split(path, ".")...)
	if findv != nil {
		cb(dxvalueToVar(findv))
		return true
	}
	return false
}

func (this *SuperValue) CheckIntFunc(path string, cb func(val int64)) bool {
	findv := this.val.ValueByPath(strings.Split(path, ".")...)
	if findv != nil {
		cb(findv.Int())
		return true
	}
	return false
}

func (this *SuperValue) CheckExistsStrFunc(path string, cb func(strv string)) bool {
	findv := this.val.ValueByPath(strings.Split(path, ".")...)
	if findv != nil {
		cb(findv.String())
		return true
	}
	return false
}

func (this *SuperValue) CheckExistsIntFunc(path string, cb func(val int64)) bool {
	findv := this.val.ValueByPath(strings.Split(path, ".")...)
	if findv != nil {
		cb(findv.Int())
		return true
	}
	return false
}

func (this *SuperValue) CheckStrFunc(path string, cb func(strv string)) bool {
	strv := this.StringByPath(path, "")
	if len(strv) > 0 {
		cb(strv)
		return true
	}
	return false
}

func (this *SuperValue) Exists(name string) bool {
	val := this.val.ValueByName(name)
	return val != nil
}

func (this *SuperValue) ExistsByPath(path string) bool {
	val := this.val.ValueByPath(strings.Split(path, ".")...)
	return val != nil
}

func (this *SuperValue) ArrayAppendValue(val interface{}) *SuperValue {
	return this.SetIndexValue(-1, val)
}

/**
 * -1:添加值
 */
func (this *SuperValue) SetIndexValue(idx int, val interface{}) *SuperValue {
	switch s := val.(type) {
	case time.Time:
		this.val.SetIndexTime(idx, s)
	case string:
		this.val.SetIndexString(idx, s)
	case int:
		this.val.SetIndexInt(idx, int64(s))
	case int8:
		this.val.SetIndexInt(idx, int64(s))
	case int16:
		this.val.SetIndexInt(idx, int64(s))
	case int32:
		this.val.SetIndexInt(idx, int64(s))
	case int64:
		this.val.SetIndexInt(idx, s)
	case uint:
		this.val.SetIndexInt(idx, int64(s))
	case uint8:
		this.val.SetIndexInt(idx, int64(s))
	case uint16:
		this.val.SetIndexInt(idx, int64(s))
	case uint32:
		this.val.SetIndexInt(idx, int64(s))
	case float32:
		this.val.SetIndexFloat(idx, s)
	case float64:
		this.val.SetIndexDouble(idx, s)
	case bool:
		this.val.SetIndexBool(idx, s)
	case *SuperValue:
		this.val.SetIndexValue(idx, s.val)
	case nil:
		this.val.SetIndexString(idx, "")
	default:
		this.val.SetIndexString(idx, gobase.GetStrValue(s, ""))
	}

	return this
}

func (this *SuperValue) AppendObject() *SuperValue {
	val := this.val.Append(dxsvalue.VT_Object)
	return NewSVFromVal(val)
}

func (this *SuperValue) AppendObjectFromByte(data []byte) error {
	json, err := dxsvalue.NewValueFromJson(data, true, false)
	if err != nil {
		return err
	} else {
		this.val.SetIndexValue(-1, json)
		return nil
	}
}

func (this *SuperValue) AppendObjectFromByteEx(data []byte) (*SuperValue, error) {
	json, err := dxsvalue.NewValueFromJson(data, true, false)
	if err != nil {
		return nil, err
	} else {
		this.val.SetIndexValue(-1, json)
		return NewSVFromVal(json), nil
	}
}

func (this *SuperValue) ValueByName(name string) *SuperValue {
	val := this.val.ValueByName(name)
	if val == nil {
		return nil
	}
	return NewSVFromVal(val)
}

func (this *SuperValue) ValueByIndex(idx int) *SuperValue {
	val := this.val.ValueByIndex(idx)
	return NewSVFromVal(val)
}

func (this *SuperValue) RemoveKey(name string) {
	this.val.RemoveKey(name)
}

func (this *SuperValue) RemoveIndex(idx int) {
	this.val.RemoveIndex(idx)
}

func (this *SuperValue) Reset() {
	this.val.Reset(this.val.DataType)
}

func (this *SuperValue) Clear() {
	if this.val != nil {
		dxsvalue.FreeValue(this.val)
		this.val = nil
	}
}

func (this *SuperValue) SaveFile(filename string, format bool) error {
	return Value2File(this.val, filename, false, false, format)
}

/*
*

	过滤, 排序, 然后调用cb, 不改变内部顺序
*/
func (this *SuperValue) SortAndRange(filter func(key string, val *SuperValue) bool,
	less_sortfunc func(key1 string, val1 *SuperValue, key2 string, val2 *SuperValue) bool,
	cb func(key string, val *SuperValue) bool) {

	type SKV struct {
		Key string
		Val *SuperValue
	}

	var lst = make([]*SKV, 0, this.Count())
	for i := 0; i < this.Count(); i++ {
		rec := SKV{
			Key: this.KeyNameByIndex(i),
			Val: this.ValueByIndex(i),
		}
		if filter != nil {
			if filter(rec.Key, rec.Val) {
				lst = append(lst, &rec)
			}
		} else {
			lst = append(lst, &rec)
		}
	}

	if less_sortfunc != nil {
		sort.Slice(lst, func(i, j int) bool {
			return less_sortfunc(lst[i].Key, lst[i].Val, lst[j].Key, lst[j].Val)
		})
	}

	if cb != nil {
		for i := 0; i < len(lst); i++ {
			if !cb(lst[i].Key, lst[i].Val) {
				break
			}
		}
	}

}

/*
**

	用;分割
*/
func (this *SuperValue) RangeFields(fields string, fn func(key string, val *SuperValue) bool) int {
	if len(fields) == 0 {
		return 0
	}
	if !strings.HasSuffix(fields, ";") {
		fields += ";"
	}

	n := 0
	j := 0

	// dxsvalue是用的for查找name
	for i := 0; i < this.Count(); i++ {
		key := this.KeyNameByIndex(i)
		if strings.Contains(fields, key+";") {
			n++
			if !fn(key, this.ValueByIndex(i)) {
				break
			}
		}
		j++
	}
	return n
}

func (this *SuperValue) RangeFieldsStrV(fields string, fn func(key string, val string) bool) int {
	if len(fields) == 0 {
		return 0
	}
	if this.val == nil {
		return 0
	}

	if !strings.HasSuffix(fields, ";") {
		fields += ";"
	}

	n := 0

	// dxsvalue是用的for查找name
	for i := 0; i < this.Count(); i++ {
		key := this.KeyNameByIndex(i)
		if strings.Contains(fields, key+";") {
			n++
			val := this.val.ValueByIndex(i)
			if !fn(key, val.String()) {
				break
			}
		}
	}
	return n
}

func (this *SuperValue) CopyFromCache(src *SuperValue, usecache bool) int {
	j := 0
	if src.IsArray() {
		if this.Count() > 0 {
			this.val.Clear()
		}
		for i := 0; i < src.val.Count(); i++ {
			v := src.val.ValueByIndex(i)
			if v == nil {
				this.val.SetIndexValue(i, nil)
			} else {
				this.val.SetIndexValue(i, v.Clone(usecache))
			}
			j++
		}
	} else {
		for i := 0; i < src.val.Count(); i++ {
			v := src.val.ValueByIndex(i)
			if v == nil {
				this.val.SetKeyValue(src.val.KeyNameByIndex(i), nil)
			} else {
				this.val.SetKeyValue(src.val.KeyNameByIndex(i), v.Clone(usecache))
			}
			j++
		}
	}
	return j
}

func (this *SuperValue) CopyFrom(src *SuperValue) int {
	j := 0
	if src.IsArray() {
		if this.Count() > 0 {
			this.val.Clear()
		}
		for i := 0; i < src.val.Count(); i++ {
			v := src.val.ValueByIndex(i)
			if v == nil {
				this.val.SetIndexValue(i, nil)
			} else {
				this.val.SetIndexValue(i, v.Clone(true))
			}
			j++
		}
	} else {
		for i := 0; i < src.val.Count(); i++ {
			v := src.val.ValueByIndex(i)
			if v == nil {
				this.val.SetKeyValue(src.val.KeyNameByIndex(i), nil)
			} else {
				this.val.SetKeyValue(src.val.KeyNameByIndex(i), v.Clone(true))
			}
			j++
		}
	}
	return j
}

/*
copy 只有src存在的值
*/
func (this *SuperValue) CopyFromIfNotExists(src *SuperValue) int {
	j := 0
	for i := 0; i < src.val.Count(); i++ {
		v := src.val.ValueByIndex(i)
		keyname := src.val.KeyNameByIndex(i)
		if !this.Exists(keyname) {
			if v != nil {
				this.val.SetKeyValue(keyname, v.Clone(true))
				j++
			}
		}
	}
	return j
}

func (this *SuperValue) CopyFromURLString(s string) int {
	n := 0
	lst := strings.Split(s, "&")
	for i := 0; i < len(lst); i++ {
		k, v := gobase.Split2Str(lst[i], "=")
		k, _ = url.QueryUnescape(k)
		v, _ = url.QueryUnescape(v)
		if len(k) > 0 {
			this.SetKeyValues(k, v)
			n++
		}
	}
	return n
}

func (this *SuperValue) CopyFromStrMap(strMap gobase.StrMap) int {
	j := 0
	for k, v := range strMap {
		this.SetKeyValue(k, v)
		j++
	}
	return j
}

func (this *SuperValue) Write2StrMap(strMap gobase.StrMap) int {
	j := 0
	this.Range(func(key string, val *SuperValue) bool {
		strMap[key] = val.String()
		return true
	})
	return j
}

func (this *SuperValue) CopyFromRef(src *SuperValue) int {
	j := 0
	if src == nil || src.val == nil {
		return 0
	}
	for i := 0; i < src.val.Count(); i++ {
		this.val.SetKeyValue(src.val.KeyNameByIndex(i), src.val.ValueByIndex(i))
		j++
	}
	return j
}

func (this *SuperValue) Range(cb func(key string, val *SuperValue) bool) int {
	j := 0
	for i := 0; i < this.Count(); i++ {
		if !cb(this.KeyNameByIndex(i), this.ValueByIndex(i)) {
			break
		}
		j++
	}
	return j
}

/*
**

	检测所有字段的值是否都为空
	fields用;分割
	如果不存在也会返回true
*/
func (this *SuperValue) IfAllFieldsIsEmpty(fields string) bool {
	j := 0

	// n为循环了多少个字段
	n := this.RangeFieldsStrV(fields, func(key string, val string) bool {
		if len(val) == 0 {
			j++
			return true
		}
		return false
	})
	// j为空值的字段
	return j == n
}

func (this *SuperValue) SaveFile2(filename string, format, escapestr bool) error {
	return Value2File(this.val, filename, false, escapestr, format)
}

func (this *SuperValue) CheckSetValue(key string, val interface{}) bool {
	if this.VarByName(key) != val {
		this.SetKeyValue(key, val)
		return true
	}
	return false
}

//func (this *SuperValue) SetStringByPath(path string, val interface{}) *SuperValue {
//
//}

func (this *SuperValue) SetKeyValue(key string, val interface{}) {
	switch s := val.(type) {
	case time.Time:
		this.val.SetKeyInt(key, s.Unix())
	case string:
		this.val.SetKeyString(key, s)
	case int:
		this.val.SetKeyInt(key, int64(s))
	case int8:
		this.val.SetKeyInt(key, int64(s))
	case int16:
		this.val.SetKeyInt(key, int64(s))
	case int32:
		this.val.SetKeyInt(key, int64(s))
	case int64:
		this.val.SetKeyInt(key, s)
	case uint:
		this.val.SetKeyInt(key, int64(s))
	case uint8:
		this.val.SetKeyInt(key, int64(s))
	case uint16:
		this.val.SetKeyInt(key, int64(s))
	case uint32:
		this.val.SetKeyInt(key, int64(s))
	case uint64:
		this.val.SetKeyInt(key, int64(s))
	case float32:
		this.val.SetKeyDouble(key, float64(s))
	case float64:
		this.val.SetKeyDouble(key, s)
	case bool:
		this.val.SetKeyBool(key, s)
	case *SuperValue:
		if s != nil {
			this.val.SetKeyValue(key, s.val)
		}
	case nil:
	default:
		//this.val.SetKeyString(key, gobase.GetStrValue(s, ""))
		reflectv := reflect.ValueOf(val)
		if reflectv.IsValid() {
			kind := reflectv.Kind()
			switch kind {
			case reflect.String:
				this.val.SetKeyString(key, reflectv.String())
				return
			case reflect.Int, reflect.Int32, reflect.Int16, reflect.Int8, reflect.Int64:
				this.val.SetKeyInt(key, reflectv.Int())
				return
			case reflect.Uint, reflect.Uint32, reflect.Uint16, reflect.Uint8, reflect.Uint64:
				this.val.SetKeyInt(key, int64(reflectv.Uint()))
				return
			}
		}
		this.val.SetKeyvalue(key, val, this.val.ValueCache())
	}

	return
}

func (this *SuperValue) KeyNameByIndex(idx int) string {
	return this.val.KeyNameByIndex(idx)
}

//func (this *SuperValue) VariantByIndex(idx int) interface{} {
//	return dxvalueToVar(this.val.ValueByIndex(idx))
//}

func (this *SuperValue) innerFindByPath(path string) *dxsvalue.DxValue {
	return this.val.ValueByPath(strings.Split(path, ".")...)
}

func (this *SuperValue) Variant() interface{} {
	return dxvalueToVar(this.val)
}

func (this *SuperValue) String() string {
	if this.val == nil {
		return ""
	}
	if this.val.DataType == dxsvalue.VT_Object || this.val.DataType == dxsvalue.VT_Array {
		return this.AsJSONStringEx(false, true)
	}
	return this.val.String()
}

func (this *SuperValue) Int() int {
	return int(this.val.Int())
}

func (this *SuperValue) Int64() int64 {
	return this.val.Int()
}

func (this *SuperValue) DateTime() time.Time {
	return valAsDateTime(this.val, gobase.ZeroTime)
}

func (this *SuperValue) Bool() bool {
	return this.val.Bool()
}

func (this *SuperValue) Float64() float64 {
	return this.val.Double()
}

func (this *SuperValue) Float32() float32 {
	return this.val.Float()
}

func (this *SuperValue) AsString(name string, def string) string {
	return this.StringByName(name, def)
}

func (this *SuperValue) AsInt(name string, def int) int {
	obj := this.val.ValueByName(name)
	if obj == nil {
		return def
	}
	if obj.DataType == dxsvalue.VT_String || obj.DataType == dxsvalue.VT_RawString {
		return gobase.StrToIntDef(obj.String(), def)
	}
	return this.val.AsInt(name, def)
}

func (this *SuperValue) AsBool(name string, def bool) bool {
	obj := this.val.ValueByName(name)
	if obj == nil {
		return def
	}
	if obj.DataType == dxsvalue.VT_String || obj.DataType == dxsvalue.VT_RawString {
		return gobase.TryStrToBool(obj.String(), def)
	}
	return obj.Bool()
}

func (this *SuperValue) AsDuration(name string, def time.Duration) time.Duration {
	obj := this.val.ValueByName(name)
	if obj == nil {
		return def
	}
	if obj.DataType == dxsvalue.VT_String || obj.DataType == dxsvalue.VT_RawString {
		return gobase.ParseDurationEx(obj.String(), def)
	}
	return time.Duration(obj.Int())
}

func (this *SuperValue) AsInt64(name string, def int64) int64 {
	obj := this.val.ValueByName(name)
	if obj == nil {
		return def
	}
	if obj.DataType == dxsvalue.VT_String || obj.DataType == dxsvalue.VT_RawString {
		return gobase.StrToInt64Def(obj.String(), def)
	}
	return obj.Int()
}

func (this *SuperValue) AsFloat32(name string, def float32) float32 {
	obj := this.val.ValueByName(name)
	if obj == nil {
		return def
	}
	if obj.DataType == dxsvalue.VT_String || obj.DataType == dxsvalue.VT_RawString {
		return gobase.StrToFloat32Def(obj.String(), def)
	}
	return obj.Float()
}

func (this *SuperValue) AsFloat64(name string, def float64) float64 {
	obj := this.val.ValueByName(name)
	if obj == nil {
		return def
	}
	if obj.DataType == dxsvalue.VT_String || obj.DataType == dxsvalue.VT_RawString {
		return gobase.StrToFloat64Def(obj.String(), def)
	}
	return obj.Double()
}

func (this *SuperValue) AsDateTime(name string, def time.Time) time.Time {
	v := this.val.Find(name)
	return valAsDateTime(v, def)
}

func (this *SuperValue) Count() int {
	return this.val.Count()
}

// [1,3,4,5,6,7,8,9,"",0,10]
func (this *SuperValue) AsStringList(ignoreEmpty bool) []string {
	rval := make([]string, 0, this.val.Count())
	for i := 0; i < this.val.Count(); i++ {
		str := this.val.StringByIndex(i, "")
		if len(str) > 0 || !ignoreEmpty {
			rval = append(rval, str)
		}
	}
	return rval
}

func (this *SuperValue) StringByNameEmpty(name string, ifempty string) string {
	str := this.StringByName(name, ifempty)
	if len(str) == 0 {
		return ifempty
	}
	return str
}

func (this *SuperValue) StringByName(name string, def string) string {
	val := this.val.ValueByName(name)
	return dxvalueToStr(val, def)
}

func (this *SuperValue) Int8ByName(name string, def int8) int8 {
	return int8(this.AsInt64(name, int64(def)))
}

func (this *SuperValue) Int8ByPath(path string, def int8) int8 {
	return int8(this.Int64ByPath(path, int64(def)))
}

func (this *SuperValue) Uint8ByName(name string, def uint8) uint8 {
	return uint8(this.AsInt64(name, int64(def)))
}

func (this *SuperValue) IntByName(name string, def int) int {
	return int(this.AsInt64(name, int64(def)))
}

func (this *SuperValue) BoolByName(name string, def bool) bool {
	return gobase.TryStrToBool(this.val.StringByName(name, ""), def)
}

func (this *SuperValue) Int64ByName(name string, def int64) int64 {
	return this.AsInt64(name, def)
}

func (this *SuperValue) DurationByName(name string, def time.Duration) time.Duration {
	return this.AsDuration(name, def)
}

func (this *SuperValue) Float32ByName(name string, def float32) float32 {
	return this.AsFloat32(name, def)
}

func (this *SuperValue) Float64ByName(name string, def float64) float64 {
	return this.AsFloat64(name, def)
}

func (this *SuperValue) DateTimeByName(name string, def time.Time) time.Time {
	return this.AsDateTime(name, def)
}

func (this *SuperValue) DateTimeByNameLocal(name string) time.Time {
	return this.AsDateTime(name, zeroTime.Local())
}

func (this *SuperValue) StringByPath(path string, def string) string {
	return this.val.StringByPath(def, strings.Split(path, ".")...)
}

func (this *SuperValue) IntByPath(path string, def int) int {
	return int(this.val.IntByPath(int64(def), strings.Split(path, ".")...))
}

func (this *SuperValue) BoolByPath(path string, def bool) bool {
	return gobase.TryStrToBool(this.StringByPath(path, ""), def)
}

func (this *SuperValue) DurationByPath(path string, def time.Duration) time.Duration {
	obj := this.innerFindByPath(path)
	if obj == nil {
		return def
	}
	if obj.DataType == dxsvalue.VT_String || obj.DataType == dxsvalue.VT_RawString {
		return gobase.ParseDurationEx(obj.String(), def)
	}
	return time.Duration(obj.Int())
}

func (this *SuperValue) Int64ByPath(path string, def int64) int64 {
	obj := this.innerFindByPath(path)
	if obj == nil {
		return def
	}
	if valIsString(obj) {
		return gobase.StrToInt64Def(obj.String(), def)
	}
	return obj.Int()
}

func (this *SuperValue) Float32ByPath(path string, def float32) float32 {
	obj := this.innerFindByPath(path)
	if obj == nil {
		return def
	}
	if valIsString(obj) {
		return gobase.StrToFloat32Def(obj.String(), def)
	}
	return obj.Float()
}

func (this *SuperValue) Float64ByPath(path string, def float64) float64 {
	obj := this.innerFindByPath(path)
	if obj == nil {
		return def
	}
	if valIsString(obj) {
		return gobase.StrToFloat64Def(obj.String(), def)
	}
	return obj.Double()
}

func (this *SuperValue) DateTimeByPath(path string, def time.Time) time.Time {
	v := this.val.ValueByPath(strings.Split(path, ".")...)
	return valAsDateTime(v, def)
}

func (this *SuperValue) AsStringByIndex(idx int, def string) string {
	val := this.val.ValueByIndex(idx)
	return dxvalueToStr(val, def)
}

func (this *SuperValue) AsIntByIndex(idx int, def int) int {
	val := this.val.ValueByIndex(idx)
	if val == nil {
		return def
	}
	if valIsString(val) {
		return gobase.StrToIntDef(val.String(), def)
	}
	return int(val.Int())
}

func (this *SuperValue) AsBoolByIndex(idx int, def bool) bool {
	val := this.val.ValueByIndex(idx)
	if val == nil {
		return def
	}
	if valIsString(val) {
		return gobase.TryStrToBool(val.String(), def)
	}
	return val.Bool()
}

func (this *SuperValue) AsInt64ByIndex(idx int, def int64) int64 {
	val := this.val.ValueByIndex(idx)
	if val == nil {
		return def
	}
	if valIsString(val) {
		return gobase.StrToInt64Def(val.String(), def)
	}
	return val.Int()
}

func (this *SuperValue) AsFloat32ByIndex(idx int, def float32) float32 {
	return this.val.FloatByIndex(idx, def)
}

func (this *SuperValue) AsFloat64ByIndex(idx int, def float64) float64 {
	return this.val.DoubleByIndex(idx, def)
}

func (this *SuperValue) AsDateTimeByIndex(idx int, def time.Time) time.Time {
	v := this.val.ValueByIndex(idx)
	return valAsDateTime(v, def)
}

func (this *SuperValue) SetKeyValues(kvPairs ...interface{}) {
	l := len(kvPairs)
	if l%2 != 0 { // 长度必须是双数
		panic("kv Pairs 长度必须是双数")
	}
	j := 0
	i := 0
	for i < l {
		if key, ok := kvPairs[i].(string); ok {
			val := kvPairs[i+1]
			this.SetKeyValue(key, val)
			j++
		}
		i += 2
	}
}
